comment ^
 fof upx unpacking here are a few important parts
 
 UPX1:004140E1                 mov     [ebx], eax      <--- write API address to IAT
 UPX1:004140E3                 add     ebx, 4

 and

 UPX1:004140EE                 popa
 UPX1:004140EF                 jmp     near ptr dword_401084 <--- jmp oep

 Now simple find those addresses and enjoy... (static on all UPX versions)...
 
 UPX1:00413FA0                 pusha
 UPX1:00413FA1                 mov     esi, offset dword_40F000
 
                               S verom u Boga, deroko/ARTeam
^
                        .586p
                        .model  flat, stdcall
                        locals

include                 c:\tasm32\include\shitheap.inc
include                 c:\tasm32\include\extern.inc


imp_patch               equ     141h
oep_patch               equ     14fh

                        .data
pinfo                   process_information     <>
sinfo                   startupinfo             <>
ctx                     context                 <>

target                  db      "unupxme.exe", 0
dump                    db      "dumped_upx.exe", 0

is_mem                  dd      ?               ;memory for import_structs

peheader                db      1024    dup(0)
imagebase               dd      ?
imagesize               dd      ?
infinite                db      0ebh, 0feh
orig_ep                 dd      ?
entrypoint              dd      ?
dummy                   dd      ?

new_iat_sec_size        dd      ?
num_of_iid              dd      ?

dump_fsize              dd      ?

fhandle                 dd      ?
shandle                 dd      ?
mhandle                 dd      ?

public  C       start
start:                 
;grab important data from PE of target process
                        call    CreateFileA, o target, GENERIC_READ, 0,0, OPEN_EXISTING, 0, 0
                        xchg    eax, esi
                        call    ReadFile, esi, o peheader, 1024, esp, 0
                        call    CloseHandle, esi
                        
                        mov     ebx, offset peheader
                        add     ebx, [ebx+3ch]
                        
                        mov     eax, [ebx.pe_imagebase]
                        mov     imagebase, eax
                        add     eax, [ebx.pe_addressofentrypoint]
                        mov     entrypoint, eax
                        mov     eax, [ebx.pe_sizeofimage]
                        mov     imagesize, eax

;createprocess and store jmp $ hooks + find oep                        
                        call    CreateProcessA, o target, 0,0,0,0, CREATE_SUSPENDED, 0,0, o sinfo, o pinfo
                        
                        mov     eax, entrypoint
                        add     eax, imp_patch
                        call    WriteProcessMemory, pinfo.pi_hProcess, eax, o infinite, 2, 0
                        
                        mov     ebx, entrypoint
                        add     ebx, oep_patch+1
                        call    ReadProcessMemory, pinfo.pi_hProcess, ebx, o dummy, 4, 0
                        
                        add     dummy, ebx
                        add     dummy, 4
                        push    dummy
                        pop     orig_ep
                        
                        dec     ebx
                        call    WriteProcessMemory, pinfo.pi_hProcess, ebx, o infinite, 2, 0
                        
                        mov     eax, entrypoint
                        add     eax, imp_patch
                        mov     patch_data1, eax
                        mov     eax, entrypoint
                        add     eax, oep_patch
                        mov     patch_data2, eax
                        
                        mov     ctx.context_ContextFlags, CONTEXT_FULL

;allocate a lots of memory for import_struct array... import_strycts are very big so we need
;a lots of memory for them...                        
                        call    VirtualAlloc, 0, 1000000h, MEM_COMMIT, PAGE_READWRITE
                        mov     is_mem, eax
                        xchg    eax, ebx

;get_system_dir will get path of system32 directory so each .dll from
;system32 is loged as "dllname", without system32 path... (import.asm)                        
                        call    get_system_dir

                        call    ResumeThread, pinfo.pi_hThread
                        
__cycle_loop:           call    Sleep, 50
                        call    GetThreadContext, pinfo.pi_hThread, o ctx
                        cmp     ctx.context_eip, 0deadc0deh
patch_data1             =       dword ptr $-4                        
                        jnz     __skip0
                        
                        call    SuspendThread, pinfo.pi_hThread
                        ;emulate mov [ebx], eax
                        call    WriteProcessMemory, pinfo.pi_hProcess, ctx.context_ebx, o ctx.context_eax, 4, 0

;address where firstthunk is.... save it's RVA in import_struct.is_address                        
                        mov     eax, ctx.context_ebx
                        sub     eax, imagebase
                        mov     [ebx.is_address], eax

;locate dll name from API address and copy it to import_struct.is_dllname
;also store it's len into import_struct.is_len                        
                        mov     eax, ctx.context_eax
                        call    locate_dll
                        lea     edi, [ebx.is_dllname]
                        mov     esi, eax
                        call    copy_string
                        mov     [ebx.is_dlllen], ecx

;locate API using it's pointer. Note that if MSB is set API is only exported as ordinal
;so for ordinal store size of API = 4 and store ordinal in import_struct.is_apiname
;if we have name store it in import_struct.is_apiname and it's len into import_struct.is_apilen                        
                        mov     eax, ctx.context_eax
                        call    locate_api
                        test    eax, 80000000h
                        jnz     __ordinal
                        lea     edi, [ebx.is_apiname]
                        mov     esi, eax
                        call    copy_string
                        mov     [ebx.is_apilen], ecx
                        jmp     __set_ctx
                        
__ordinal:              mov     dword ptr[ebx.is_apiname], eax
                        mov     [ebx.is_apilen], 4
                        
__set_ctx:              add     ctx.context_eip, 2
                        call    SetThreadContext, pinfo.pi_hThread, o ctx
                        call    ResumeThread, pinfo.pi_hThread
                        
                        add     ebx, size import_struct
                        
__skip0:                cmp     ctx.context_eip, 0deadc0deh
patch_data2             =       dword ptr $-4
                        jne     __cycle_loop

;here comes dumping code...                        
                        call    SuspendThread, pinfo.pi_hThread

;
;handle forwarded imports if any
;
                        call    handle_forwards, is_mem
;get_imp_size returned data are used to calculate size of new import section
;eax has size of new import section
;ecx has number of IIDs (image_import_descriptors)+ 1 for 0 terminating
;for each API one image_import_descriptor is created... this is due to logic
;of my dumps... so I can see in static disassembly which api is which...
;if you have any doubts check my tuts about TheMida, ASProtect, Armadillo at 
;http://tutorials.accessroot.com                        
                        call    get_imp_size, is_mem
                        
                        mov     new_iat_sec_size, eax
                        mov     num_of_iid, ecx
                        
                        mov     ebx, imagesize
                        add     ebx, eax
                        mov     dump_fsize, ebx

;dump file from memory and create needed sections                                                 
                        call    CreateFileA, o dump, GENERIC_READ or GENERIC_WRITE, 0,0, CREATE_ALWAYS, 0, 0
                        mov     fhandle, eax
                        call    CreateFileMappingA, eax, 0, PAGE_READWRITE, 0, ebx, 0
                        mov     shandle, eax
                        call    MapViewOfFile, eax, FILE_MAP_ALL_ACCESS, 0, 0, ebx
                        mov     mhandle, eax
                        
                        call    ReadProcessMemory, pinfo.pi_hProcess, imagebase, mhandle, imagesize, 0
                        
                        mov     ebx, mhandle
                        add     ebx, [ebx+3ch]
                        mov     [ebx.pe_numberofsections], 2
                        push    dump_fsize
                        pop     [ebx.pe_sizeofimage]
                        
                        lea     eax, [ebx+0f8h]
                        mov     edx, imagesize
                        sub     edx, 1000h
                        
                        mov     [ebx.pe_baseofcode], 1000h
                        mov     [ebx.pe_sizeofcode], edx
                        
                        mov     [eax.sh_sizeofrawdata], edx
                        mov     [eax.sh_virtualsize], edx
                        mov     [eax.sh_virtualaddress], 1000h
                        mov     [eax.sh_pointertorawdata], 1000h
                        mov     [eax.sh_characteristics], 0E0000020h
                        mov     dword ptr[eax],'mud.'
                        mov     dword ptr[eax+4], ' dep'
                        
                        add     eax, size image_section_header
                        mov     edx, imagesize
                        mov     [eax.sh_virtualaddress], edx
                        mov     [eax.sh_pointertorawdata], edx
                        mov     edx, new_iat_sec_size
                        mov     [eax.sh_virtualsize], edx
                        mov     [eax.sh_sizeofrawdata], edx
                        mov     [eax.sh_characteristics], 0E0000020h
                        mov     dword ptr[eax],'pmi.'
                        mov     dword ptr[eax+4], ' tro'
                        
                        xchg    eax, edx

;here we are building new_import_table in buffer which is allocated by build_import_table
;it receives RVA of import_section, pointer to import_struct array, size of new iat section
;and number of iids (last 2 values are obtained by get_imp_size procedure)                        
                        call    build_import_table, [edx.sh_virtualaddress], is_mem, new_iat_sec_size, num_of_iid
                        
                        mov     edi, [edx.sh_pointertorawdata]
                        add     edi, mhandle
                        mov     esi, eax
                        mov     ecx, new_iat_sec_size
                        cld
                        rep     movsb
                        
                        mov     eax, [edx.sh_virtualaddress]
                        mov     [ebx.pe_import], eax

;last important part is to adjust all firstthunks in dump, it will only copy data from originalfirstthunk
;to firstthunk in dump...                         
                        mov     eax, mhandle
                        call    adjust_first_thunk
                        
                        mov     eax, orig_ep
                        sub     eax, imagebase
                        mov     [ebx.pe_addressofentrypoint], eax 

                        call    UnmapViewOfFile, mhandle
                        call    CloseHandle, shandle
                        call    CloseHandle, fhandle
                        call    TerminateProcess, pinfo.pi_hProcess, 0
                        call    ExitProcess, 0

;copy string and receive it's size in ecx (useful for is_apiname/is_apilen and is_dllname/is_dlllen)
copy_string:            push    eax
                        xor     ecx, ecx
__c_s:                  lodsb
                        stosb           
                        inc     ecx                
                        test    al, al
                        jnz     __c_s
                        pop     eax
                        retn

include                 .\import.asm                     
                        end     start                 